package org.aeon.fasttasks.core.manager;

import org.aeon.fasttasks.core.Task;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.io.Closeable;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author aeon
 * @createTime 2025/08/05  14:30
 * @description
 */


public class TaskContext {

    /**
     * 任务计数器
     */
    private final AtomicInteger taskCounter;

    /**
     * 序号
     */
    private final int serNum;

    /**
     * 任务名称
     */
    private final Task task;

    /**
     * 相关注释
     */
    private final Map<Class<? extends Annotation>, Annotation> annotations;

    /**
     * 可关闭
     */
    private final List<? extends Closeable> closeables;

    /**
     * 是否开始
     */
    private final AtomicBoolean start = new AtomicBoolean(false);

    /**
     * 是否完成
     */
    private final AtomicBoolean completed = new AtomicBoolean(false);

    /**
     * 未出现异常情况
     */
    private final AtomicBoolean correct = new AtomicBoolean(true);

    /**
     * 多任务完成状态
     */
    private final MultiStateLatch multiStateLatch;

    /**
     * 任务数据
     */
    private final Map<Object, Object> taskData;

    /**
     * 前置任务(可选)
     * 在该任务完成后执行本任务
     */
    private TaskExpansion[] frontEndTasks;

    /**
     * 开始执行时间
     */
    private long startTime;

    /**
     * 执行时间
     */
    private long executionTime;

    /**
     * 批量工作线程池
     */
    private ThreadPoolTaskExecutor batchWorkTasksExecutor;

    /**
     * 任务调度线程池
     */
    private ThreadPoolTaskExecutor bossTasksExecutor;

    /**
     * 延迟任务调度线程池
     */
    private ThreadPoolTaskScheduler tasksScheduler;


    /**
     * 新任务用构造器
     *
     * @param task
     * @param annotations
     * @param closeables
     * @param isMultiState
     */
    public TaskContext(Task task,
                       Map<Class<? extends Annotation>, Annotation> annotations,
                       List<? extends Closeable> closeables,
                       boolean isMultiState) {
        this.task = task;
        this.annotations = annotations;
        this.closeables = closeables;
        this.taskData = new ConcurrentHashMap<>();

        if (isMultiState) {
            this.multiStateLatch = MultiStateLatch.of(completed);
            this.taskCounter = new AtomicInteger(0);
            this.serNum = taskCounter.getAndIncrement();
        } else {
            this.multiStateLatch = MultiStateLatch.of();
            this.taskCounter = null;
            this.serNum = 0;
        }
    }

    /**
     * 拷贝任务用构造器
     *
     * @param taskCounter
     * @param task
     * @param annotations
     * @param closeables
     * @param multiStateLatch
     * @param taskData
     */
    public TaskContext(AtomicInteger taskCounter,
                       Task task,
                       Map<Class<? extends Annotation>, Annotation> annotations,
                       List<? extends Closeable> closeables,
                       MultiStateLatch multiStateLatch,
                       Map<Object, Object> taskData) {
        this.taskCounter = taskCounter;
        this.serNum = taskCounter.getAndIncrement();
        this.task = task;
        this.annotations = annotations;
        this.closeables = closeables;
        this.multiStateLatch = multiStateLatch.add(completed);
        this.taskData = taskData;
    }

    public AtomicInteger getTaskCounter() {
        return taskCounter;
    }

    public int getSerNum() {
        return serNum;
    }

    public Task getTask() {
        return task;
    }

    public Map<Class<? extends Annotation>, Annotation> getAnnotations() {
        return annotations;
    }

    public List<? extends Closeable> getCloseables() {
        return closeables;
    }

    public boolean isStart() {
        return start.get();
    }

    void setStart(boolean start) {
        this.start.set(start);
    }

    AtomicBoolean getCompleted() {
        return completed;
    }

    public boolean isCompleted() {
        return completed.get();
    }

    void setCompleted(boolean completed) {
        this.completed.set(completed);
    }

    public boolean isCorrect() {
        return correct.get();
    }

    void setCorrect(boolean correct) {
        this.correct.set(correct);
    }

    public long getStartTime() {
        return startTime;
    }

    void setStartTime(long startTime) {
        this.startTime = startTime;
    }

    public long getExecutionTime() {
        return executionTime;
    }

    void setExecutionTime(long executionTime) {
        this.executionTime = executionTime;
    }

    public List<TaskExpansion> getFrontEndTasks() {
        return Objects.isNull(frontEndTasks) ? List.of() : List.of(frontEndTasks);
    }

    void setFrontEndTasks(TaskExpansion... frontEndTasks) {
        this.frontEndTasks = frontEndTasks;
    }

    public Map<Object, Object> getTaskData() {
        return taskData;
    }

    @SuppressWarnings("unchecked")
    public <V> V getTaskData(Object key) {
        return (V) taskData.get(key);
    }

    @SuppressWarnings("unchecked")
    public <V> V putTaskData(Object key, V value) {
        return (V) taskData.put(key, value);
    }

    public MultiStateLatch getMultiStateLatch() {
        return multiStateLatch;
    }

    public ThreadPoolTaskExecutor getBatchWorkTasksExecutor() {
        return batchWorkTasksExecutor;
    }

    public void setBatchWorkTasksExecutor(
            ThreadPoolTaskExecutor batchWorkTasksExecutor) {
        this.batchWorkTasksExecutor = batchWorkTasksExecutor;
    }

    public ThreadPoolTaskExecutor getBossTasksExecutor() {
        return bossTasksExecutor;
    }

    public void setBossTasksExecutor(ThreadPoolTaskExecutor bossTasksExecutor) {
        this.bossTasksExecutor = bossTasksExecutor;
    }

    public ThreadPoolTaskScheduler getTasksScheduler() {
        return tasksScheduler;
    }

    public void setTasksScheduler(ThreadPoolTaskScheduler tasksScheduler) {
        this.tasksScheduler = tasksScheduler;
    }
}
